package org.mtmi.tuio;
import java.util.ArrayList;
import java.util.List;
import org.mtmi.ui.controls.ITouchableControl;






/*A Trace represents a collection of Cursors, i.e. the path of a finger in the TUIOManager.*/

public class Trace {

	private static int idCounter = 0;
	private int id;
	public States state;
	private List<CursorPoint> cursorPointsList;
	private CursorPoint firstCursorPointInTrace, lastCursorPointInTrace;
	private ITouchableControl initialTarget;

	// A trace is alive when its last cursor in the path is in the state ADDED
	// or UPDATED.
	// When the cursor is removed the trace dies, but it can "resurrect" if
	// another ADDED cursor
	// is added to the path.
	private boolean isAlive;

	

	public enum States {

		// cursor added, the trace has born
		ADDED,
		// cursor updated
		UPDATED,
		// cursor removed
		REMOVED,
		// cursor added, the trace has resurrected
		RESET,
		// when it was removed since at least a time equal to
		// Settings.TRACE_TIME_GAP
		TERMINATED
	}

	// Getters and Setters

	public int getId() {
		return id;
	}

	public States getState() {
		return state;
	}

	public void setState(States mState) {
		state = mState;
	}

	public CursorPoint getFirst() {
		return firstCursorPointInTrace;
	}

	public CursorPoint getLast() {
		return lastCursorPointInTrace;
	}

	public List<CursorPoint> getPath() {
		return cursorPointsList;
	}

	public int count() {
		return cursorPointsList.size();
	}

	public boolean isAlive() {
		return isAlive;
	}

	// Target lists
	public ITouchableControl getInitialTarget() {
		return initialTarget;
	}

	


	public Trace(CursorPoint cursor, ITouchableControl target) {
		super();

		id = idCounter++;
		cursorPointsList = new ArrayList<CursorPoint>();
		cursorPointsList.add(cursor);
		firstCursorPointInTrace = lastCursorPointInTrace = cursor;
		state = States.ADDED;
		isAlive = true;
		initialTarget = target;
		
		
		
	}

	// Append adding or updating Cursor
	void addAddedOrUpdatedCursor(CursorPoint cursor) {
		
		UpdateCursorValues(cursor);
		cursorPointsList.add(cursor);
		lastCursorPointInTrace = cursor;

		if (state == States.REMOVED) {
			state = States.RESET;
			isAlive = true;
		} else
			state = States.UPDATED;

	}

	// Appending a removed Cursor
	public void addRemovedCursor(CursorPoint cursor) {

		UpdateCursorValues(cursor);

		// Add a removed cursor to the cursorPoints list
		cursorPointsList.add(cursor);
		// We added a removed cursor so this is the last cursor in a trace
		lastCursorPointInTrace = cursor;
		// We added a removed cursor so the trace is not alive ( but is not dead
		// , it can resurrect)
		isAlive = false;
		// We added a removed cursor so the trace state is REMOVED
		state = States.REMOVED;

	 
	}
	
	

	// Terminate
	public void terminate() {
		state = States.TERMINATED;
	}

	// Update cursor value
	private void UpdateCursorValues(CursorPoint cursor) {
		
		
		if (state != States.REMOVED) {
			double dt = (double) (cursor.timestamp() - lastCursorPointInTrace
					.timestamp()) / 1000;
			double xSpeed = ((double) cursor.getX() - (double) lastCursorPointInTrace
					.getX())
					/ dt;
			double ySpeed = ((double) cursor.getY() - (double) lastCursorPointInTrace
					.getY())
					/ dt;
			double motionSpeed = Math.sqrt(xSpeed * xSpeed + ySpeed * ySpeed);
			double motionAccel = (motionSpeed - (double) lastCursorPointInTrace
					.motionSpeed())
					/ dt;
			cursor.cXSpeed = (float) xSpeed;
			cursor.cYSpeed = (float) ySpeed;
			cursor.cMotionSpeed = (float) motionSpeed;
			cursor.cMotionAccel = (float) motionAccel;
		}
	}

}
